<?php

namespace Leikes\Utils\ModelUtil;

use Illuminate\Database\Eloquent\Model;
use Leikes\Utils\Exceptions\ModelUtil\QueryException;
use Leikes\Utils\Exceptions\ModelUtil\StoreException;
use Leikes\Utils\Exceptions\ModelUtil\UpdateException;
use Leikes\Utils\Exceptions\ModelUtil\DeleteException;
use Illuminate\Support\Arr;

trait ModelOperatorTrait{
	/**
	 * 使用该特质必须使用此方法返回模型
	 *
	 * @return     Model  ( description_of_the_return_value )
	 */
	abstract protected function model();

	/**
	 * 是否调用抽象方法的模型，还是调用方法传回来的模型
	 *
	 * @param      <type>   $model  The model
	 *
	 * @return     boolean  True if has model, False otherwise.
	 */
	private function hasModel($model = null){
		if($model != null){
			$model = $model;
		}
		else{
			$model = $this->model();
		}

		return $model;
	}

	/**
	 * 根据模型唯一标识查找数据
	 *
	 * @param      <type>                               $id     The identifier
	 * @param      array                                $with   The with
	 * @param      \Illuminate\Database\Eloquent\Model  $model  The model
	 *
	 * @return     <type>                               ( description_of_the_return_value )
	 */
	public function findModel($id,$with = [],Model $model = null){

		// try {
			$model = $this->hasModel($model);

			return $model->with($with)->find($id);
		// } catch (\Exception $e) {
		// 	throw new QueryException($e);
		// }
		
	}

	/**
	 * 根据条件返回非数据对象
	 *
	 * @param      array                                $conditions  The conditions
	 * @param      array                                $with        The with
	 * @param      \Illuminate\Database\Eloquent\Model  $model       The model
	 *
	 * @return     \Illuminate\Database\Eloquent\Model  ( description_of_the_return_value )
	 */
	public function queryModel(array $conditions,array $with = [],Model $model = null){
		// try {
			$model = $this->hasModel($model);

			$fillable = $model->getFillable();

			if(is_array($model->getKeyName())){
				foreach ($model->getKeyName() as $primaryKey) {
					array_push($fillable,$primaryKey);
				}
			}
			else{
				array_push($fillable,$model->getKeyName());
			}

			array_push($fillable,$model->getCreatedAtColumn());

			array_push($fillable,$model->getUpdatedAtColumn());

			$query = $model->query()->with($with);

			if(count($conditions) > 0){
				if(is_array($fillable) && !is_null($fillable) && count($fillable) > 0){
					$conditions = Arr::only($conditions, $fillable);
				}

				foreach ($conditions as $key => $value) {
					if(is_array($value)){
						if(count($value) == 1 && array_key_exists('like', $value)){
							$query->where($key,'like','%'. $value['like'] .'%');
						}
						elseif(count($value) == 2 && array_key_exists('start_time', $value) && array_key_exists('end_time', $value)){

							$query->where($key,'>=',$value['start_time'])->where($key,'<=',$value['end_time']);
						}
						else{
							$query->whereIn($key,$value);
						}
					}
					else{
						$query->where($key, $value);
					}
				}
			}

			return $query;
		// } catch (\Exception $e) {
		// 	throw new QueryException($e);
		// }
	}

	/**
	 * 非主键查找单条数据
	 *
	 * @param      array                                $conditions  The conditions
	 * @param      array                                $with        The with
	 * @param      \Illuminate\Database\Eloquent\Model  $model       The model
	 *
	 * @return     <type>                               ( description_of_the_return_value )
	 */
	public function firstModel(array $conditions,array $with = [],Model $model = null,$withTrashed = false){
		// try {
			$query = $this->queryModel($conditions,$with,$model);

			if($withTrashed){
				$query->withTrashed();
			}

			return $query->first();
		// } catch (\Exception $e) {
		// 	throw new QueryException($e);
		// }
		
	}

	/**
	 * 分页
	 *
	 * @param      array                                $conditions  The conditions
	 * @param      array                                $with        The with
	 * @param      \Illuminate\Database\Eloquent\Model  $model       The model
	 * @param      <type>                               $orderBy     The order by
	 *
	 * @return     <type>                               ( description_of_the_return_value )
	 */
	public function pageModel(array $conditions,array $with = [],Model $model = null,$orderBy = 'created_at'){
		// try {
			$query = $this->queryModel($conditions,$with,$model);
			
			if($orderBy != null){
				$query = $query->orderBy($orderBy,'DESC');
			}
			
			if(request()->has('page')){
				$pageSize = 10;
	            if(request()->has('pageSize')){
	                $pageSize = request()->pageSize;
	            }
				return $query->paginate($pageSize);
			}
			else{
				return $query->get();
			}
		// } catch (\Exception $e) {
		// 	throw new QueryException($e);
		// }
	}

	/**
	 * 根据主键修改
	 *
	 * @param      <type>                               $id     The identifier
	 * @param      <type>                               $data   The data
	 * @param      \Illuminate\Database\Eloquent\Model  $model  The model
	 *
	 * @return     <type>                               ( description_of_the_return_value )
	 */
	public function updatePrimaryKeyModel($id,$data,Model $model = null){
		// try {
			$findData = $updateObj = $this->findModel($id,[],$model);

			$updateObj = $updateObj->update($data);

			return $findData;
		// } catch (\Exception $e) {
		// 	throw new UpdateException($e);
		// }
		
	}

	/**
	 * 根据非主键类型返回单挑数据进行修改
	 *
	 * @param      array                                $conditions  The conditions
	 * @param      array                                $with        The with
	 * @param      \Illuminate\Database\Eloquent\Model  $model       The model
	 *
	 * @return     <type>                               ( description_of_the_return_value )
	 */
	public function updateConditionsModel(array $conditions,$data,array $with = [],Model $model = null){
		// try {
			$updateObj = $this->firstModel($conditions,$with,$model);

			if(isset($updateObj)){
				$updateObj = $updateObj->update($data);
			}

			return $updateObj;
		// } catch (\Exception $e) {
		// 	throw new UpdateException($e);
		// }
	}

	/**
	 * 新增数据
	 *
	 * @param      <type>                               $data   The data
	 * @param      \Illuminate\Database\Eloquent\Model  $model  The model
	 *
	 * @return     <type>                               ( description_of_the_return_value )
	 */
	public function storeModel($data,Model $model = null){
		// try {
			$model = $this->hasModel($model);

			$fillable = $model->getFillable();

			if(is_array($fillable) && !is_null($fillable) && count($fillable) > 0){
				$data = Arr::only($data, $fillable);
			}

			return $model->create($data);

		// } catch (\Exception $e) {
		// 	throw new StoreException($e);
		// }
	}

	/**
	 * 根据主键删除数据
	 *
	 * @param      <type>                               $id     The identifier
	 * @param      \Illuminate\Database\Eloquent\Model  $model  The model
	 */
	public function deletePrimaryKeyModel($id,Model $model = null){
		// try {
			$deleteObj = $this->findModel($id);

			$deleteObj->delete();
		// } catch (\Exception $e) {
		// 	throw new DeleteException($e);
		// }
	}

	/**
	 * 非主键类型删除单条数据
	 *
	 * @param      array                                $conditions  The conditions
	 * @param      \Illuminate\Database\Eloquent\Model  $model       The model
	 */
	public function deleteConditionsModel(array $conditions,Model $model = null){
		// try {
			$deleteObj = $this->firstModel($conditions,[],$model);

			$deleteObj->delete();

		// } catch (\Exception $e) {
		// 	throw new DeleteException($e);
		// }
	}

	/**
	 * 批量删除数据
	 *
	 * @param      array                                $conditions  The conditions
	 * @param      \Illuminate\Database\Eloquent\Model  $model       The model
	 */
	public function dropModel(array $conditions,Model $model = null,$withTrashed = false){
		// try {
			$query = $this->queryModel($conditions,[],$model);

			if($withTrashed){
				$query->withTrashed();

				$dropDatas = $query->get();

				foreach($dropDatas as $dropData){
					$dropData->forceDelete();
				}
			}
			else{
				$dropDatas = $query->get();

				foreach($dropDatas as $dropData){
					$dropData->delete();
				}
			}
		// } catch (\Exception $e) {
		// 	throw new DeleteException($e);
		// }
	}
}